package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private IArticleClient client;
    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) throws Exception {
        //1.根据id获取数据
        WmNews wmNews = wmNewsMapper.selectById(id);
        //2.判断数据状态
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }


        //3.完成机械审核的判断
        if (wmNews.getStatus()==1) {
            //3.1抽取文章中的文本数据和图片数据
            Map<String, Object> date = handTextImage(wmNews);
            //3.0自定义铭感词检验
           Boolean isSensitiveScan = handleSensitiveScan(date.get("text").toString(), wmNews);
            if (!isSensitiveScan) {
                return;
            }
            //3.2发送文本数据到阿里云进行审核
            Boolean isTextScan = handleTextScan(date.get("text").toString(), wmNews);
            if (!isTextScan) {
                return;
            }
            //3.3下载所有的图片数据 发送到阿里云进行审核
            Boolean isImageScan = handleImageScan((List<String>) date.get("imge"), wmNews);
            if (!isImageScan) {
                return;
            }
            //3.4调用feign请求完成数据同步
            ResponseResult responseResult = sveApArticle(wmNews);
            //3.5更新文章状态和ap_article表中的id到自媒体文章 的表中
            if (!responseResult.getCode().equals("200"))
            {
                throw  new CustomException(AppHttpCodeEnum.SERVER_ERROR);
            }
            wmNews.setArticleId(Long.parseLong(responseResult.getData().toString()));
            updateWmNewStatus(wmNews,(short) 9,"文章审核通过");
        }
    }

    /**
     * 自定义铭感词
     * @param text
     * @param wmNews
     * @return
     */
    private Boolean handleSensitiveScan(String text, WmNews wmNews) {
        Boolean flag = true;
        //1.查询铭感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitive = wmSensitives.stream().map(string -> string.getSensitives()).collect(Collectors.toList());
        //2.初始化DFA的最大的map
        SensitiveWordUtil.initMap(sensitive);
        log.info("初始化后的map:{}",sensitive);
        //3.使用DFA算法进行校验
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);

     if (map!=null&&map.size()!=0)
     {
         flag=false;
         updateWmNewStatus(wmNews,(short)2,"文章中存在铭感词"+map);
     }

        //返回校验结果
        return flag;
    }

    /**
     * 通过Feign请求同步数据
     *
     * @param wmNews
     * @return
     */
    private ResponseResult sveApArticle(WmNews wmNews) {

        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, dto);
        dto.setLayout(wmNews.getType());
        //查询作者信息
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            dto.setAuthorName(wmUser.getName());
            dto.setAuthorId(wmNews.getUserId());
        }

        //查询频道信息
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null) {
            dto.setChannelName(wmChannel.getName());
            dto.setChannelId(wmNews.getChannelId());
        }
        ResponseResult responseResult = client.saveArticle(dto);
        return responseResult;
    }

    /**
     * 图片审核
     *
     * @param imge
     * @param wmNews
     * @return
     */
    private Boolean handleImageScan(List<String> imge, WmNews wmNews) throws Exception {
        Boolean flag = true;
        if (imge == null || imge.size() == 0) {
            return flag;
        }

        //1.先对图片数据进行数据去重
        imge = imge.stream().distinct().collect(Collectors.toList());
        //2.从minio中下载图片
        List<byte[]> imagelist = new ArrayList<>(imge.size());
        for (String image : imge) {
            byte[] bytes = fileStorageService.downLoadFile(image);
            imagelist.add(bytes);
        }
        //3.把图片数据一起打包发给阿里云审核,并解析状态
        Map map = greenImageScan.imageScan(imagelist);
        flag = getaBoolean(wmNews, flag, map, "图片有违规内容");
        return flag;
    }

    /**
     * 文本审核
     *
     * @param text
     * @param wmNews
     * @return
     * @throws Exception
     */
    private Boolean handleTextScan(String text, WmNews wmNews) throws Exception {
        Boolean flag = true;
        Map map = greenTextScan.greeTextScan(text);
        flag = getaBoolean(wmNews, flag, map, "文章有违规内容");
        return flag;
    }

    /**
     * 解析数据方法
     *
     * @param wmNews
     * @param flag
     * @param map
     * @return
     */
    private Boolean getaBoolean(WmNews wmNews, Boolean flag, Map map, String reason) {
        if (map != null) {

            //审核失败
            if ("block".equals(map.get("suggestion").toString())) {
                //更新文章状态为2(审核失败)
                updateWmNewStatus(wmNews, (short) 2, reason );
                flag = false;
            } else if ("review".equals(map.get("suggestion"))) {
                updateWmNewStatus(wmNews, (short) 3, reason );
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 修改状态
     *
     * @param wmNews
     * @param i
     * @param reason
     */
    private void updateWmNewStatus(WmNews wmNews, short i, String reason) {
        wmNews.setStatus(i);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }


    /**
     * 抽取文章中的图片数据和文本数据
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handTextImage(WmNews wmNews) {
        //保存文本
        StringBuffer stringBuffer = new StringBuffer();
        //保存图片
        List<String> image = new ArrayList<>();
        //组装数据
        if (StringUtils.isNotEmpty(wmNews.getContent())) {
            List<Map> list = JSON.parseArray(wmNews.getContent(), Map.class);
            for (Map map : list) {
                if ("image".equals(map.get("type"))) {
                    image.add(map.get("value").toString());
                } else if ("text".equals(map.get("type"))) {
                    stringBuffer.append(map.get("value").toString());
                }
            }
        }
        //stringBuffer添加标题数据
        stringBuffer.append(wmNews.getTitle().toString());

        //添加封面图片
        if (StringUtils.isNotEmpty(wmNews.getImages())) {
            String[] split = wmNews.getImages().split(".");
            image.addAll(Arrays.asList(split));
        }
        Map<String, Object> date = new HashMap<>();
        date.put("text", stringBuffer);
        date.put("imge", image);
        return date;
    }
}
